package top.scauwlt.spring;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import top.scauwlt.annotation.RpcReference;
import top.scauwlt.annotation.RpcService;
import top.scauwlt.config.RpcServiceConfig;
import top.scauwlt.factory.SingletonFactory;
import top.scauwlt.provider.ServiceProvider;
import top.scauwlt.provider.impl.ServiceProviderImpl;
import top.scauwlt.proxy.RpcClientProxy;
import top.scauwlt.remoting.transport.client.NettyRpcClient;
import top.scauwlt.remoting.transport.server.NettyRpcServer;

import java.lang.reflect.Field;

/**
 * 类的后置处理，主要做两件事情
 * 1.如果该Bean被RpcService注解，则在初始化前发布该服务，使用到serviceProvider
 * 2.如果该Bean中有被RpcReference注解的属性，则在初始化后通过动态代理将该Bean置换为对应的代理类，使用到NettyRpcClient
 *
 * @Author wmm
 * @Date 2022/7/27 17:51
 */
@Slf4j
@Component
public class SpringBeanPostProcessor implements BeanPostProcessor {
    @Autowired
    private ServiceProvider serviceProvider;

    public SpringBeanPostProcessor() {
        //serviceProvider = SingletonFactory.getInstance(ServiceProviderImpl.class);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(RpcService.class)) {
            RpcService annotation = bean.getClass().getAnnotation(RpcService.class);
            RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
                    .version(annotation.version())
                    .group(annotation.group())
                    .service(bean)
                    .build();
            serviceProvider.publishService(rpcServiceConfig);
            log.info("serviceProvider: {}", serviceProvider);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {


        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(RpcReference.class)) {
                RpcReference reference = field.getAnnotation(RpcReference.class);
                RpcServiceConfig rpcServiceConfig = RpcServiceConfig.builder()
                        .version(reference.version())
                        .group(reference.group())
                        .service(bean).build();
                RpcClientProxy rpcClientProxy = new RpcClientProxy(rpcServiceConfig);
                Object proxy = rpcClientProxy.getProxy(field.getType());
                field.setAccessible(true);
                try {
                    field.set(bean, proxy);
                } catch (IllegalAccessException e) {
                    log.error("reflect error: ", e.getMessage());
                }
            }
        }
        return bean;
    }

}
